<?php

class Common_Chart extends Common_DataObject {

    const DIMENSION_DEFAULT_HEIGHT = 125;
    const DIMENSION_DEFAULT_WIDTH = 250;

    const DIMENSION_THUMBNAIL_HEIGHT = 22;
    const DIMENSION_THUMBNAIL_WIDTH = 50;

    const TYPE_PIE                          = 'pie';
    const TYPE_LINE                         = 'line';
    const TYPE_TREND                        = 'trend-line';
    const TYPE_TREND_VERTICAL_BAR_GROUPED   = 'trend-bar-grouped';
    const TYPE_TREND_VERTICAL_BAR_STACKED   = 'trend-bar-stacked';
    const TYPE_VERTICAL_BAR_GROUPED         = 'vertical-bar-grouped';
    const TYPE_VERTICAL_BAR_STACKED         = 'vertical-bar-stacked';
    const TYPE_HORIZONTAL_BAR_GROUPED       = 'horizontal-bar-grouped';
    const TYPE_HORIZONTAL_BAR_DYNAMIC       = 'horizontal-bar-dynamic';
    const TYPE_RADAR                        = 'radar';
    const TYPE_ANALOG                       = 'analog';
    const TYPE_SCATTER                      = 'scatter';
    const TYPE_SCATTER_TREND                = 'scatter-trend';

    const LEGEND_POSITION_TOP = 't';
    const LEGEND_POSITION_TOP_VERTICAL = 'tv';
    const LEGEND_POSITION_BOTTOM = 'b';
    const LEGEND_POSITION_BOTTOM_VERTICAL = 'bv';
    const LEGEND_POSITION_RIGHT = 'r';
    const LEGEND_POSITION_LEFT = 'l';

    const DEFAULT_TEMPLATE = 'chart/simple';
    const DEFAULT_TEMPLATE_THUMBNAIL = 'chart/thumbnail';
    
    const DEFAULT_LINE_SIZE = 1;
    const DEFAULT_DATA_ROTATION = 0;

    const FEATURE_3D_VERSION        = '3d_version';
    const FEATURE_LINE_SIZE         = 'line_size';
    const FEATURE_DATA_ROTATION     = 'data_rotation';
    const FEATURE_LEGEND_POSITION   = 'legend_position';
    const FEATURE_ZERO_YAXIS        = 'zero_yaxis';
    const FEATURE_COLOUR_PER_ITEM   = 'colour_per_item';

    private $int_height = null;
    private $int_width = null;

    private $obj_strategy = null;

    private static $arr_default_colours = array('FF9900');

    public function __construct($obj_strategy) {
        parent::__construct();
        $this->obj_strategy = $obj_strategy;
    }

    protected function get_strategy() {
       return $this->obj_strategy;
    }
    
    public function get_chart_type() {
        return $this->get_strategy()->get_chart_type();
    }

    public function has_feature($str_feature_key) {
        return $this->get_strategy()->has_feature($str_feature_key);
    }

    public function bind($arr_data, $arr_headers = array()) {

        if(is_array($arr_data)) {

            // ensure data is structure as a series of arrays.  ie:
            // array (
            //     'series1' => array(...),
            //     'series2' => array(...)
            // )

            $mix_bottom = end($arr_data);
            if(!is_array($mix_bottom)) {
                $arr_data = array($arr_data);
            }

            // each strategy may interpret/modify the data and headers as
            // necessary, so send these variables to the strategy
            $this->get_strategy()->bind($arr_data, $arr_headers);

            /*if(isset($arr_meta['series'])) {
                $arr_series = $arr_meta['series'];
                $this->get_strategy()->set_series($arr_series);
                unset($arr_meta['series']);
            }*/
            
        }

    }

    public function get_headers() {
        return $this->get_strategy()->get_headers();
    }

    public function get_series() {
        return $this->get_strategy()->get_series();
    }
    
    public function count_data_points() {
        return $this->get_strategy()->count_data_points();
    }

    public function set_render_options($arr_options) {

        if(isset($arr_options['caption'])) {
            $this->set_caption($arr_options['caption']);
            unset($arr_options['caption']);
        }

        if(isset($arr_options['source'])) {
            $this->set_source($arr_options['source']);
            unset($arr_options['source']);
        }

        //----------------------------------------------------------------------

        $this->get_strategy()->merge_render_options($arr_options);

    }

    public function render($arr_options = array()) {

        $arr_options = array_merge($this->get_strategy()->get_render_options(), $arr_options);
        
        if(!isset($arr_options['caption'])) {
            $arr_options['caption'] = $this->getCaption();
        }

        if(isset($arr_options['width']) && ($arr_options['width'] <= 0)) {
            unset($arr_options['width']);
        }
        if(!isset($arr_options['width'])) {
            $arr_options['width'] = $this->get_width();
        }

        if(isset($arr_options['height']) && ($arr_options['height'] <= 0)) {
            unset($arr_options['height']);
        }
        if(!isset($arr_options['height'])) {
            $arr_options['height'] = $this->get_height();
        }

        if(!isset($arr_options['colours'])) {
            $arr_options['colours'] = $this->get_default_colours();
        }

        //----------------------------------------------------------------------

        if(isset($arr_options['resample_data'])) {
            $int_size = (int) $arr_options['resample_data'];
            if($int_size <= 1) {
                unset($arr_options['resample_data']);
            }
        }   
        
        //----------------------------------------------------------------------
        
        $str_chart_source = null;

        if(isset($arr_options['chart_type'])) {
            $obj_strategy = $this->get_strategy()->convert_chart_type($arr_options['chart_type']);

            if(!is_null($obj_strategy)) {
                $str_chart_source = $obj_strategy->get_chart_source($arr_options);
            }
            
        }

        if(empty($str_chart_source)) {
            
            $str_chart_source = $this->get_strategy()->get_chart_source($arr_options);

        }

        //----------------------------------------------------------------------

        $arr_meta = $this->getProperties();
        
        if(isset($arr_options['caption'])) {
            $arr_meta['caption'] = $arr_options['caption'];
        }

        if(isset($arr_options['source'])) {
            $arr_meta['source'] = $arr_options['source'];
        }

        //----------------------------------------------------------------------

        $str_template = 'chart/default';
        if(isset($arr_options['template'])) {
            $str_template = $arr_options['template'];
        }
        $str_template .= '.phtml';

        $obj_template = new Common_Template();

        // remove any array elements whose indexing key starts with an underscore,
        // because leaving these will cause a problem when the template/view tries
        // to assign its variables within its object scope
        //$arr_options = Common_Utility_ArrayFunctions::remove_elements_matching_key_pattern($arr_options, '/^_.*/i');

        $obj_template->assign($arr_options);

        $obj_template->assign(array(
            'str_chart_source' => $str_chart_source,
            'arr_meta'         => $arr_meta,
            'int_sampling_size' => $this->get_strategy()->get_sampling_size()
        ));

        return $obj_template->render($str_template);

    }

    public function render_thumbnail($arr_options = array()) {

        $arr_options = array_merge($this->get_strategy()->get_render_options(), $arr_options);
        
        $arr_options['width'] = self::DIMENSION_THUMBNAIL_WIDTH;
        $arr_options['height'] = self::DIMENSION_THUMBNAIL_HEIGHT;

        if(!isset($arr_options['colours'])) {
            $arr_options['colours'] = $this->get_default_colours();
        }

        //----------------------------------------------------------------------

        $arr_options['include_labels'] = false;

        $str_chart_source = $this->get_strategy()->get_thumbnail_source($arr_options);

        //----------------------------------------------------------------------

        $arr_meta = $this->get_meta();

        if(isset($arr_options['caption'])) {
            $arr_meta['caption'] = $arr_options['caption'];
        }

        if(isset($arr_options['source'])) {
            $arr_meta['source'] = $arr_options['source'];
        }

        //----------------------------------------------------------------------

        $str_template = self::DEFAULT_TEMPLATE_THUMBNAIL;
        if(isset($arr_options['template'])) {
            $str_template = $arr_options['template'];
        }
        $str_template .= '.phtml';

        $obj_template = new Common_Template();

        $obj_template->assign(array(
            'str_chart_source' => $str_chart_source,
            'arr_meta' => $arr_meta
        ));

        return $obj_template->render($str_template);
        
    }

    public function count_data_series() {
        return $this->get_strategy()->count_data_series();
    }

    public function publish_to_file($str_file, $arr_options = array()) {

        if(isset($arr_options['width']) && ($arr_options['width'] <= 0)) {
            unset($arr_options['width']);
        }
        if(!isset($arr_options['width'])) {
            $arr_options['width'] = $this->get_width();
        }

        if(isset($arr_options['height']) && ($arr_options['height'] <= 0)) {
            unset($arr_options['height']);
        }
        if(!isset($arr_options['height'])) {
            $arr_options['height'] = $this->get_height();
        }

        $this->get_strategy()->publish_to_file($str_file, $arr_options);

    }

    protected function export_for_serialise() {

        $arr_export = parent::export_for_serialise();
        $arr_export = array_merge($arr_export, array(
            'type'     => $this->get_strategy()->get_strategy_type(),
            'chart'    => $this->get_strategy()->get_chart_type(),
            'strategy' => $this->get_strategy()->export_for_serialise(),
            'width'    => $this->get_width(),
            'height'   => $this->get_height()
        ));

        return $arr_export;
    }

    static public function unserialise($str) {

        $obj_chart = null;

        $arr_decoded = self::decode_for_unserialise($str);
        if(is_array($arr_decoded)) {

            $enm_strategy   = $arr_decoded['type'];
            $enm_chart_type = $arr_decoded['chart'];

            $obj_chart = Common_Chart_Factory::create($enm_chart_type, $enm_strategy, $arr_decoded);

        }

        return $obj_chart;
    }

    static public function set_default_colours($arr_colours) {
        if(is_array($arr_colours)) {
            self::$arr_default_colours = $arr_colours;
        }

    }

    static public function get_default_colours() {
        return self::$arr_default_colours;
    }


    public function set_width($int_width) {
        $int_width = (int) $int_width;
        if($int_width > 0) {
            $this->int_width = $int_width;
        }
    }

    public function get_width() {
        $int = !is_null($this->int_width) ? $this->int_width : null;
        if(is_null($int)) {
            $int = self::DIMENSION_DEFAULT_WIDTH;
        }
        return $int;
    }

    public function get_dynamic_width() {
        return $this->get_strategy()->get_dynamic_width();
    }

    public function set_height($int_height) {
        $int_height = (int) $int_height;
        if($int_height > 0) {
            $this->int_height = $int_height;
        }
    }

    public function get_height() {
        $int = !is_null($this->int_height) ? $this->int_height : null;
        if(is_null($int)) {
            $int = self::DIMENSION_DEFAULT_HEIGHT;
        }
        return $int;
    }

    public function get_dynamic_height() {
        return $this->get_strategy()->get_dynamic_height();
    }

    public function set_dimension(Common_Chart_Dimension $obj_dimension) {

        $int_height = $obj_dimension->get_height();
        $int_width = $obj_dimension->get_width();

        if(!is_null($int_height) && !is_null($int_width)) {
            $this->set_height($int_height);
            $this->set_width($int_width);
        }

    }

}
